# TypeScript 的编译原理
我们的学习从本节开始进入了新的阶段,之前我们的所有内容只停留在 TypeScript 的使用阶段,而真正的 TypeScript 高手是可以定制 TypeScript 的,笔者也不是这方面的高手,只花两节的内容能粗略介绍下,只当做抛砖引玉。
我们都知道 Babel,他是 JavaScript 的转化工具,比如可以把 ES6+ 的代码转化成 ES5 的代码,我们开发者可以通过 Babel 暴露的接口来编写插件,通过插件我们可以自己定制JavaScript。
而 TypeScript 在 2.3 版本也暴露了相关的接口给开发者,允许开发者控制部分 JavaScript 的代码生产,因此,同样我们也可以通过编写 TypeScript Transformer Plugin 的方式控制最终生成的 js 代码。
在正式编写 TypeScript Transformer Plugin 之前,我们必须了解一些前置知识,那就是TypeScript的一些简单的编译原理知识。
# 编译器的组成
TypeScript有自己的编译器,这个编译器主要有以下部分组成:
- Scanner 扫描器
- Parser 解析器
- Binder 绑定器
- Emitter 发射器
- Checker 检查器
# 编译器的处理
扫描器通过扫描源代码生成token流:
SourceCode(源码)+ 扫描器 --> Token 流
解析器将token流解析为抽象语法树(AST):
Token 流 + 解析器 --> AST(抽象语法树)
绑定器将AST中的声明节点与相同实体的其他声明相连形成符号(Symbols),符号是语义系统的主要构造块:
AST + 绑定器 --> Symbols(符号)
检查器通过符号和AST来验证源代码语义:
AST + 符号 + 检查器 --> 类型验证
最后我们通过发射器生成JavaScript代码:
AST + 检查器 + 发射器 --> JavaScript 代码
# 编译器处理流程
TypeScript 的编译流程也可以粗略得分为三步:
- 解析
- 转换
- 生成
结合上部分的编译器各个组成部分,流程如下图:

我们主要控制的要编写的 transformer Plugin 作用于 Emitter 阶段.
# 抽象语法树
我们先了解一下抽象语法树是怎么来的,举个简单的例子,比如我们写一段变量声明的代码var a = ...,它要经历这样几个步骤:
- 字符流转化为被定义过的tokenliu
- 线性token流被转化为抽象语法树
